package cn.lg.soar.database.base.service.impl;

import cn.lg.soar.common.constant.SymbolConstants;
import cn.lg.soar.common.exceptions.BaseAException;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.ParameterUtil;
import cn.lg.soar.common.util.data.StringUtil;
import cn.lg.soar.database.base.entity.IPathTreeEntity;
import cn.lg.soar.database.base.entity.PathTreeEntity;
import cn.lg.soar.database.base.service.IPathTreeService;
import cn.lg.soar.database.config.DatabaseProperties;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public abstract class PathTreeServiceImpl<ID extends Serializable, M extends BaseMapper<T>, T extends IPathTreeEntity<ID>>
        extends BaseServiceImpl<M, T>
        implements IPathTreeService<ID, T> {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DatabaseProperties properties;

    private volatile String updateLinkSql;

    public abstract ID getRootId();

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSort(ID id, int sort) {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(PathTreeEntity.SORT, sort).eq(this.getIdField(), id);
        AssertUtil.isTrue(super.update(updateWrapper), "修改排序失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void resetSort() {
        UpdateWrapper<T> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(PathTreeEntity.SORT, 0);
        AssertUtil.isTrue(super.update(updateWrapper), "重置排序失败");
    }

    @Override
    public List<T> getAncestorList(String ancestorLink) {
        if (StringUtil.isBlank(ancestorLink)) {
            return Collections.emptyList();
        }
        String[] split = ancestorLink.split(IPathTreeEntity.ANCESTOR_LINK_JOIN);
        return this.listByIds(Arrays.asList(split));
    }

    @Override
    public List<T> getInferiorsList(ID id) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>()
                .like(IPathTreeEntity.ANCESTOR_LINK, id + IPathTreeEntity.ANCESTOR_LINK_JOIN);
        return this.list(queryWrapper);
    }

    @Override
    public List<T> getInferiorsAndSelfList(ID id) {
        ParameterUtil.notNull(id, "id 不能为空");
        T t = this.getById(id);
        if (t == null) {
            return Collections.emptyList();
        }
        List<T> list = this.getAncestorList(t.getAncestorLink());
        list.add(t);
        return list;
    }

    @Override
    public List<T> getNodePathList(ID id) {
        ParameterUtil.notNull(id, "id 不能为空");
        T t = this.getById(id);
        if (t == null) {
            return Collections.emptyList();
        }
        List<T> list = this.getAncestorList(t.getAncestorLink());
        list.add(t);
        return list;
    }

    @Override
    public boolean save(T entity) {
        this.setAncestorLink(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(T entity) {
        if (entity.getParentId() != null) {
            T t = this.baseMapper.selectById(entity.primaryKey());
            ParameterUtil.notNull(t, "数据不存在");
            if(Objects.equals(entity.getParentId(), t.getParentId())){
                return super.updateById(entity);
            }
            this.setAncestorLink(entity);

            String s1 = t.getAncestorLink() + entity.primaryKey() + SymbolConstants.GREATER_SIGN;
            String s2 = entity.getAncestorLink() + entity.primaryKey() + SymbolConstants.GREATER_SIGN;
            this.jdbcTemplate.update(this.getUpdateLinkSql(), s1, s2, "%" + entity.primaryKey() + "%");
        }
        return super.updateById(entity);
    }

    private void setAncestorLink(T t){
        if(t.getParentId() == null || t.getParentId().equals(getRootId())){
            t.setParentId(getRootId());
            t.setAncestorLink(StringUtil.EMPTY);
            return;
        }
        IPathTreeEntity<ID> parent = this.baseMapper.selectById(t.getParentId());
        if(parent == null){
            throw new BaseAException(6, "父id无效");
        }
        t.setParent(parent);
    }

    protected String getUpdateLinkSql() {
        if (updateLinkSql == null) {
            synchronized (this) {
                if (updateLinkSql == null) {
                    updateLinkSql = MessageFormat.format(
                            properties.getUpdateTreeLinkSqlTemplate(),
                            TableInfoHelper.getTableInfo(this.entityClass).getTableName(),
                            PathTreeEntity.ANCESTOR_LINK
                    );
                }
            }
        }
        return updateLinkSql;
    }

}
